﻿namespace UnityEditor
{
    using Mono.Cecil;
    using Mono.Cecil.Cil;
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Runtime.CompilerServices;

    internal class AssemblyReferenceChecker
    {
        private List<AssemblyDefinition> assemblyDefinitions = new List<AssemblyDefinition>();
        private List<string> assemblyFileNames = new List<string>();
        private HashSet<string> definedMethods = new HashSet<string>();
        private HashSet<string> referencedMethods = new HashSet<string>();
        private HashSet<string> referencedTypes = new HashSet<string>();
        private DateTime startTime = DateTime.MinValue;

        private void CollectReferencedMethods(TypeDefinition typ, HashSet<string> referencedMethods, HashSet<string> definedMethods, float progressValue)
        {
            this.DisplayProgress(progressValue);
            foreach (TypeDefinition definition in typ.NestedTypes)
            {
                this.CollectReferencedMethods(definition, referencedMethods, definedMethods, progressValue);
            }
            foreach (MethodDefinition definition2 in typ.Methods)
            {
                if (definition2.HasBody)
                {
                    foreach (Instruction instruction in definition2.Body.Instructions)
                    {
                        if (OpCodes.Call == instruction.OpCode)
                        {
                            referencedMethods.Add(instruction.Operand.ToString());
                        }
                    }
                    definedMethods.Add(definition2.ToString());
                }
            }
        }

        private void CollectReferencedMethods(AssemblyDefinition[] definitions, HashSet<string> referencedMethods, HashSet<string> definedMethods, float progressValue)
        {
            foreach (AssemblyDefinition definition in definitions)
            {
                foreach (TypeDefinition definition2 in definition.MainModule.Types)
                {
                    this.CollectReferencedMethods(definition2, referencedMethods, definedMethods, progressValue);
                }
            }
        }

        public void CollectReferences(string path, bool withMethods, float progressValue, bool ignoreSystemDlls)
        {
            this.assemblyDefinitions = new List<AssemblyDefinition>();
            string[] strArray = !Directory.Exists(path) ? new string[0] : Directory.GetFiles(path);
            foreach (string str in strArray)
            {
                if (Path.GetExtension(str) == ".dll")
                {
                    AssemblyDefinition item = AssemblyDefinition.ReadAssembly(str);
                    if (!ignoreSystemDlls || !this.IsiPhoneIgnoredSystemDll(item.Name.Name))
                    {
                        this.assemblyFileNames.Add(Path.GetFileName(str));
                        this.assemblyDefinitions.Add(item);
                    }
                }
            }
            AssemblyDefinition[] assemblies = this.assemblyDefinitions.ToArray();
            this.referencedTypes = MonoAOTRegistration.BuildReferencedTypeList(assemblies);
            if (withMethods)
            {
                this.CollectReferencedMethods(assemblies, this.referencedMethods, this.definedMethods, progressValue);
            }
        }

        private void DisplayProgress(float progressValue)
        {
            TimeSpan span = (TimeSpan) (DateTime.Now - this.startTime);
            string[] strArray = new string[] { "Fetching assembly references", "Building list of referenced assemblies..." };
            if (span.TotalMilliseconds >= 100.0)
            {
                if (EditorUtility.DisplayCancelableProgressBar(strArray[0], strArray[1], progressValue))
                {
                    throw new System.Exception(strArray[0] + " aborted");
                }
                this.startTime = DateTime.Now;
            }
        }

        public AssemblyDefinition[] GetAssemblyDefinitions()
        {
            return this.assemblyDefinitions.ToArray();
        }

        public string[] GetAssemblyFileNames()
        {
            return this.assemblyFileNames.ToArray();
        }

        public static bool GetScriptsHaveMouseEvents(string path)
        {
            AssemblyReferenceChecker checker = new AssemblyReferenceChecker();
            checker.CollectReferences(path, true, 0f, true);
            return checker.HasDefinedMethod("OnMouse");
        }

        public bool HasDefinedMethod(string methodName)
        {
            <HasDefinedMethod>c__AnonStorey48 storey = new <HasDefinedMethod>c__AnonStorey48 {
                methodName = methodName
            };
            return Enumerable.Any<string>(this.definedMethods, new Func<string, bool>(storey.<>m__A0));
        }

        public bool HasReferenceToMethod(string methodName)
        {
            <HasReferenceToMethod>c__AnonStorey47 storey = new <HasReferenceToMethod>c__AnonStorey47 {
                methodName = methodName
            };
            return Enumerable.Any<string>(this.referencedMethods, new Func<string, bool>(storey.<>m__9F));
        }

        public bool HasReferenceToType(string typeName)
        {
            <HasReferenceToType>c__AnonStorey49 storey = new <HasReferenceToType>c__AnonStorey49 {
                typeName = typeName
            };
            return Enumerable.Any<string>(this.referencedTypes, new Func<string, bool>(storey.<>m__A1));
        }

        private bool IsiPhoneIgnoredSystemDll(string name)
        {
            return ((name.StartsWith("System") || name.Equals("UnityEngine")) || name.Equals("Mono.Posix"));
        }

        public string WhoReferencesClass(string klass, bool ignoreSystemDlls)
        {
            <WhoReferencesClass>c__AnonStorey4A storeya = new <WhoReferencesClass>c__AnonStorey4A {
                klass = klass
            };
            foreach (AssemblyDefinition definition in this.assemblyDefinitions)
            {
                if (!ignoreSystemDlls || !this.IsiPhoneIgnoredSystemDll(definition.Name.Name))
                {
                    AssemblyDefinition[] assemblies = new AssemblyDefinition[] { definition };
                    if (Enumerable.Any<string>(MonoAOTRegistration.BuildReferencedTypeList(assemblies), new Func<string, bool>(storeya.<>m__A2)))
                    {
                        return definition.Name.Name;
                    }
                }
            }
            return null;
        }

        [CompilerGenerated]
        private sealed class <HasDefinedMethod>c__AnonStorey48
        {
            internal string methodName;

            internal bool <>m__A0(string item)
            {
                return item.Contains(this.methodName);
            }
        }

        [CompilerGenerated]
        private sealed class <HasReferenceToMethod>c__AnonStorey47
        {
            internal string methodName;

            internal bool <>m__9F(string item)
            {
                return item.Contains(this.methodName);
            }
        }

        [CompilerGenerated]
        private sealed class <HasReferenceToType>c__AnonStorey49
        {
            internal string typeName;

            internal bool <>m__A1(string item)
            {
                return item.StartsWith(this.typeName);
            }
        }

        [CompilerGenerated]
        private sealed class <WhoReferencesClass>c__AnonStorey4A
        {
            internal string klass;

            internal bool <>m__A2(string item)
            {
                return item.StartsWith(this.klass);
            }
        }
    }
}

